package com.ftwj.demo.utils.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.ftwj.demo.utils.logs.LoggerUtil;

/**
* <p>Title: FileHelper</p>  
* <p>Description: 描述：文件操作工具类，提供了常用的移动，复制，读写，修改，删除的功能</p>
* <p>Copyright: Copyright (c) 2020 </p>  
* <p>Company: 兰州飞天网景信息产业有限公司</p>    
* @author WangSLi
* @date 2020年4月15日 下午4:52:09
* @version V1.0
 */
public class FileHelper {

    public static final String EMPTY = "";

    public static final long ONE_KB = 1024L;
    public static final long ONE_MB = ONE_KB * ONE_KB;
    public static final long ONE_GB = ONE_KB * ONE_MB;
    public static final long ONE_TB = ONE_KB * ONE_GB;
    public static final long ONE_PB = ONE_KB * ONE_TB;
    public static final long ONE_EB = ONE_KB * ONE_PB;

    //private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 10;
    private static final int FILE_BUFFER_SIZE = 1024 * 10;

    /**
     * 	字节写入到文件中
     *
     * @param file   文件
     * @param data   字节数据
     * @param append 是否从文件后面添加
     * @throws IOException
     */
    public static void writeByteArrayToFile(File file, byte[] data, boolean append) throws IOException {
        OutputStream out = null;
        try {
            out = openOutputStream(file, append);
            out.write(data);
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    /**
     * 	读出文件中的字节
     *
     * @param file 文件
     * @return 字节数组
     * @throws IOException
     */
    public static byte[] readFileToByteArray(File file) throws IOException {
        InputStream in = null;
        try {
            in = openInputStream(file);
            return IOUtils.toByteArray(in, file.length());
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    /**
     * 	数据写入文件
     *
     * @param file     要写入的文件
     * @param data     数据
     * @param encoding 指定编码
     * @param append   是否追加
     * @throws IOException
     */
    public static void writeStringToFile(File file, String data, String encoding, boolean append) throws IOException {
        OutputStream out = null;
        try {
            out = openOutputStream(file, append);
            IOUtils.write(data, out, encoding);
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    /**
     * 	从文件中以指定编码读取成字符串
     *
     * @param file     文件
     * @param encoding 编码
     * @return
     * @throws IOException
     */
    public static String readFileToString(File file, String encoding) throws IOException {
        InputStream in = null;
        try {
            in = openInputStream(file);
            return IOUtils.toString(in, encoding);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    /**
     *	 打开一个文件的写入流，文件不存在会自动创建
     *
     * @param file   文件
     * @param append 是否以追加的方式写入
     * @return
     * @throws IOException
     */
    public static FileOutputStream openOutputStream(File file, boolean append) throws IOException {
        if (file.exists()) {
            if (file.isDirectory()) {
                throw new IOException("File '" + file + "' exists but is a directory");
            }
            if (file.canWrite() == false) {
                throw new IOException("File '" + file + "' cannot be written to");
            }
        } else {
            File parent = file.getParentFile();
            if (parent != null) {
                if (!parent.mkdirs() && !parent.isDirectory()) {
                    throw new IOException("Directory '" + parent + "' could not be created");
                }
            }
        }
        return new FileOutputStream(file, append);
    }

    /**
     * 	打开文件输入流，校验友好的提示
     *
     * @param file 要打开的文件
     * @return
     * @throws IOException
     */
    public static FileInputStream openInputStream(File file) throws IOException {
        if (file.exists()) {
            if (file.isDirectory()) {
                throw new IOException("File '" + file + "' exists but is a directory");
            }

            if (file.canRead() == false) {
                throw new IOException("File '" + file + "' cannot be read");
            }
        } else {
            throw new FileNotFoundException("File '" + file + "' does not exist");
        }

        return new FileInputStream(file);
    }

    /**
     * 	友好的显示单位
     *
     * @param size byte单位值
     * @return
     */
    public static String byteCountToDisplaySize(long size) {
        String displaySize;
        if (size / ONE_EB > 0) {
            displaySize = String.valueOf(size / ONE_EB) + " EB";
        } else if (size / ONE_PB > 0) {
            displaySize = String.valueOf(size / ONE_PB) + " PB";
        } else if (size / ONE_TB > 0) {
            displaySize = String.valueOf(size / ONE_TB) + " TB";
        } else if (size / ONE_GB > 0) {
            displaySize = String.valueOf(size / ONE_GB) + " GB";
        } else if (size / ONE_MB > 0) {
            displaySize = String.valueOf(size / ONE_MB) + " MB";
        } else if (size / ONE_KB > 0) {
            displaySize = String.valueOf(size / ONE_KB) + " KB";
        } else {
            displaySize = String.valueOf(size) + " bytes";
        }

        return displaySize;
    }

    /**
     * 	剪切文件夹到文件夹
     *
     * @param src     源文件夹
     * @param destDir 目的文件夹
     * @param isCover 存在是否覆盖
     * @throws IOException
     */
    public static void moveDirectoryToDirectory(File src, File destDir, boolean isCover) throws IOException {
        if (src == null) {
            throw new NullPointerException("Source must not be null");
        }
        if (destDir == null) {
            throw new NullPointerException("Destination directory must not be null");
        }

        if (destDir.exists()) {
            if (isCover) {
                deleteFileOrDirectoryQuietly(destDir.getPath());
            } else {
                throw new IOException("Destination directory is exists and isCover=false");
            }
        }

        destDir.mkdirs();
        if (!destDir.exists()) {
            throw new FileNotFoundException("Destination directory '" + destDir + "' create failed]");
        }
        if (!destDir.isDirectory()) {
            throw new IOException("Destination '" + destDir + "' is not a directory");
        }

        boolean rename = src.renameTo(destDir);
        if (!rename) {
            if (destDir.getCanonicalPath().startsWith(src.getCanonicalPath())) {
                throw new IOException("Cannot move directory: " + src + " to a subdirectory of itself: " + destDir);
            }
            copyDirectoryToDirectory(src, destDir);
            deleteFileOrDirectoryQuietly(src.getPath());
            if (src.exists()) {
                throw new IOException(
                        "Failed to delete original directory '" + src + "' after copy to '" + destDir + "'");
            }
        }
    }

    /**
     * 	剪切文件到文件夹
     *
     * @param srcFile 源文件
     * @param destDir 目的文件夹
     * @param isCover 存在是否覆盖
     * @throws IOException
     */
    public static void moveFileToDirectory(File srcFile, File destDir, boolean isCover) throws IOException {
        if (srcFile == null) {
            throw new NullPointerException("Source must not be null");
        }
        if (destDir == null) {
            throw new NullPointerException("Destination directory must not be null");
        }

        if (!destDir.exists()) {
            destDir.mkdirs();
        }

        if (!destDir.exists()) {
            throw new FileNotFoundException("Destination directory '" + destDir + "' create failed]");
        }

        if (!destDir.isDirectory()) {
            throw new IOException("Destination '" + destDir + "' is not a directory");
        }

        moveFile(srcFile, new File(destDir, srcFile.getName()), isCover);
    }

    /**
     * 	剪切文件到文件
     *
     * @param srcFile  源文件
     * @param destFile 目的文件
     * @param isCover  存在是否覆盖
     * @throws IOException
     */
    public static void moveFile(File srcFile, File destFile, boolean isCover) throws IOException {
        if (null == srcFile) {
            throw new NullPointerException("Source must not be null");
        }
        if (null == destFile) {
            throw new NullPointerException("Destination must not be null");
        }

        if (!srcFile.exists()) {
            throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
        }
        if (srcFile.isDirectory()) {
            throw new IOException("Source '" + srcFile + "' is a directory");
        }

        if (destFile.isDirectory()) {
            throw new IOException("Destination '" + destFile + "' is a directory");
        }

        if (destFile.exists()) {
            if (isCover) {
                deleteFileOrDirectoryQuietly(destFile.getPath());
            } else {
                throw new IOException("Destination directory is exists and isCover=false");
            }
        }

        boolean rename = srcFile.renameTo(destFile);
        if (!rename) {
            copyFile(srcFile, destFile);
            if (!srcFile.delete()) {
                deleteFileOrDirectoryQuietly(destFile.getPath());
                throw new IOException(
                        "Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'");
            }
        }
    }

    /**
     * 	拷贝文件夹到文件夹
     *
     * @param srcDir  源文件夹
     * @param destDir 目的文件夹
     * @throws IOException
     */
    public static void copyDirectoryToDirectory(File srcDir, File destDir) throws IOException {
        copyDirectoryToDirectory(srcDir, new File(destDir, srcDir.getName()), null);
    }

    /**
     * 	拷贝文件夹到文件夹
     *
     * @param srcDir  源文件夹
     * @param destDir 目的文件夹
     * @param filter  文件过滤器
     * @throws IOException
     */
    public static void copyDirectoryToDirectory(File srcDir, File destDir, FileFilter filter) throws IOException {
        if (srcDir == null) {
            throw new NullPointerException("Source must not be null");
        }
        if (destDir == null) {
            throw new NullPointerException("Destination must not be null");
        }

        if (srcDir.exists() && !srcDir.isDirectory()) {
            throw new IllegalArgumentException("Source '" + destDir + "' is not a directory");
        }
        if (destDir.exists() && !destDir.isDirectory()) {
            throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
        }

        if (!srcDir.exists()) {
            throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
        }

        if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
            throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same");
        }

        // Cater for destination being directory within the source directory
        // (see IO-141)
        List<String> exclusionList = null;
        if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) {
            File[] srcFiles = null == filter ? srcDir.listFiles() : srcDir.listFiles(filter);
            if (srcFiles != null && srcFiles.length > 0) {
                exclusionList = new ArrayList<String>(srcFiles.length);
                for (File srcFile : srcFiles) {
                    File copiedFile = new File(destDir, srcFile.getName());
                    exclusionList.add(copiedFile.getCanonicalPath());
                }
            }
        }
        doCopyDirectory(srcDir, destDir, filter, true, exclusionList);
    }

    private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter, boolean preserveFileDate,
                                        List<String> exclusionList) throws IOException {

    	File[] srcFiles = (null == filter) ? srcDir.listFiles() : srcDir.listFiles(filter);
        if (srcFiles == null) { 
            throw new IOException("Failed to list contents of " + srcDir);
        }
        if (destDir.exists()) {
            if (!destDir.isDirectory()) {
                throw new IOException("Destination '" + destDir + "' exists but is not a directory");
            }
        } else {
            if (!destDir.mkdirs() && !destDir.isDirectory()) {
                throw new IOException("Destination '" + destDir + "' directory cannot be created");
            }
        }
        if (!destDir.canWrite()) {
            throw new IOException("Destination '" + destDir + "' cannot be written to");
        }

        for (File srcFile : srcFiles) {
            File dstFile = new File(destDir, srcFile.getName());
            if (exclusionList == null || !exclusionList.contains(srcFile.getCanonicalPath())) {
                if (srcFile.isDirectory()) {
                    doCopyDirectory(srcFile, dstFile, filter, preserveFileDate, exclusionList);
                } else {
                    doCopyFile(srcFile, dstFile, preserveFileDate);
                }
            }
        }

        if (preserveFileDate) {
            destDir.setLastModified(srcDir.lastModified());
        }
    }

    /**
     * 	拷贝文件到文件夹
     *
     * @param srcFile 源文件
     * @param destDir 目的文件夹
     * @throws IOException
     */
    public static void copyFileToDirectory(File srcFile, File destDir) throws IOException {
        copyFileToDirectory(srcFile, destDir, true);
    }

    /**
     * 	拷贝文件到文件夹
     *
     * @param srcFile          源文件
     * @param destDir          目的文件夹
     * @param preserveFileDate 是否修改时间
     * @throws IOException
     */
    public static void copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate) throws IOException {
        if (null == destDir) {
            throw new NullPointerException("Destination must not be null");
        }
        if (destDir.exists() && !destDir.isDirectory()) {
            throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
        }
        File destFile = new File(destDir, srcFile.getName());
        copyFile(srcFile, destFile, preserveFileDate);
    }

    /**
     * 	拷贝文件到文件，默认修改目的文件为当前时间
     *
     * @param srcFile  源文件
     * @param destFile 目的文件
     * @throws IOException IO异常
     */
    public static void copyFile(File srcFile, File destFile) throws IOException {
        copyFile(srcFile, destFile, true);
    }

    /**
     *	 拷贝文件到文件，以下几种情况会有IO异常
     * 1. 源文件地址和目标文件地址为空
     * 2. 源文件不存在
     * 3. 源文件是个目录
     * 4. 目标文件没有写权限
     * 5. 源文件和目标文件被指向了同一个文件
     *
     * @param srcFile          源文件
     * @param destFile         目标文件
     * @param preserveFileDate 目标文件产生后，是否修改为当前时间
     * @throws IOException IO异常
     */
    public static void copyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
        if (srcFile == null) {
            throw new NullPointerException("Source must not be null");
        }
        if (destFile == null) {
            throw new NullPointerException("Destination must not be null");
        }

        if (!srcFile.exists()) {
            throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
        }
        
        // 源文件存在，但是个目录，不允许
        if (destFile.isDirectory()) {
            throw new IOException("Destination '" + destFile + "' exists but is a directory");
        }
        
        // 源文件和目标文件指向了同一个文件，不允许
        if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
            throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same");
        }
        
        // 目标文件存在，没有写权限
        if (destFile.exists() && !destFile.canWrite()) {
            throw new IOException("Destination '" + destFile + "' exists but is read-only");
        }

        // 目标文件没有父目录，就创建之
        File parentFile = destFile.getParentFile();
        if (null != parentFile) {
            if (!parentFile.mkdirs() && !parentFile.isDirectory()) {
                throw new IOException("Destination '" + parentFile + "' directory cannot be created");
            }
        }

        doCopyFile(srcFile, destFile, preserveFileDate);
    }

    private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        FileChannel input = null;
        FileChannel output = null;
        try {
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);
            input = fis.getChannel();
            output = fos.getChannel();
            long size = input.size();
            int pos = 0;
            long count = 0;
            while (pos < size) {
                count = size - pos > FILE_BUFFER_SIZE ? FILE_BUFFER_SIZE : size - pos;
                pos += output.transferFrom(input, pos, count);
            }
        } finally {
            IOUtils.closeQuietly(output);
            IOUtils.closeQuietly(fos);
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(fis);
        }

        if (srcFile.length() != destFile.length()) {
            throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile + "'");
        }
        
        // 修改文件最后修改时间
        if (preserveFileDate) {
            destFile.setLastModified(srcFile.lastModified());
        }
    }
    
    /**
     * <p>Title: deleteFile</p>  
     * <p>Description: 单文件删除（不支持文件夹删除）</p>  
     * @param path
     * @author HeYang
     * @date 2020年4月20日  
     * @version 1.0
     */
	public static boolean deleteFile(String filePath) {
		if (null != filePath && filePath.length() > 0) {
			File file = new File(filePath);
			if(file.isFile()) {
				return file.delete();
			}
			LoggerUtil.error("{} 不是一个文件，无法删除",filePath);
		}
		return false;
	}

    /**
     * 	删除指定目录下文件及目录，默认本身也会被删除(递归删除)
     *
     * @param filePath 文件或者文件夹路径
     */
    public static void deleteFileOrDirectoryQuietly(String filePath) {
        try {
            deleteFileOrDirectory(filePath, true);
        } catch (Exception e) {
            // Ignore
        }
    }

    /**
     * 	递归删除指定目录下文件及目录（包括下级目录的所有文件）
     *
     * @param filePath       文件或者文件夹路径
     * @param deleteThisPath 是否需要删除这个本身指定的文件或者文件夹
     */
    public static void deleteFileOrDirectory(String filePath, boolean deleteThisPath) throws IOException {
        if (null != filePath && filePath.length() > 0) {
            File file = new File(filePath);
            
            //如果是目录，或者子文件或目录进行递归处理
            if (file.isDirectory()) {
                File files[] = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    deleteFileOrDirectory(files[i].getAbsolutePath(), true);
                }
            }
            
            if (deleteThisPath) {
                //如果是文件，直接删除
                if (!file.isDirectory()) {
                    file.delete();
                } else {
                    //如果是目录，在判定下面没有子文件目录时删除
                    if (file.listFiles().length == 0) {
                        file.delete();
                    }
                }
            }
        }
    }
    
    /**
     * 	获取指定路径下的所有文件
     *
     * @param path 指定路径
     * @return 文件列表
     */
    public static List<File> getFileListByPath(String path) {
        return getFileListByPath(path, null);
    }

    /**
     *	 获取指定路径下的所有文件
     *
     * @param path   指定路径
     * @param filter 文件过滤器
     * @return 文件列表
     */
    public static List<File> getFileListByPath(String path, FileFilter filter) {
        File directory = new File(path);
        if (!directory.exists() || !directory.isDirectory()) {
            throw new IllegalArgumentException("Nonexistent directory[" + path + "]");
        }

        return new Recursiver().getFileList(directory, filter);
    }

    /**
     *	 读取指定路径的Properties文件
     *
     * @param path 路径
     * @return Properties对象
     */
    public static Properties readProperties(String path) {
        File file = new File(path);
        if (!file.exists()) {
            return null;
        }

        Properties properties = new Properties();
        InputStream in = null;

        try {
            in = new FileInputStream(file);
            properties.load(in);
        } catch (IOException e) {
            throw new RuntimeException("Could not read Properties[" + path + "]", e);
        } finally {
            IOUtils.closeQuietly(in);
        }

        return properties;
    }

    /**
     * 	从输入流读取Properties对象
     *
     * @param in 输入流
     * @return Properties对象
     */
    public static Properties readProperties(InputStream in) {
        Properties properties = new Properties();

        try {
            properties.load(in);
        } catch (IOException e) {
            throw new RuntimeException("Could not read Properties", e);
        } finally {
            IOUtils.closeQuietly(in);
        }

        return properties;
    }

    /**
     * 	把Properties对象写到指定路径的文件里
     *
     * @param path       文件路径
     * @param properties Properties对象
     */
    public static void writeProperties(String path, Properties properties) {
        OutputStream out = null;

        try {
            out = new FileOutputStream(path);
            properties.store(out, null);
        } catch (IOException e) {
            throw new RuntimeException("Could not write Properties[" + path + "]", e);
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    /**
     * 	递归获取指定目录下的所有文件的遍历器
     *
     */
    private static class Recursiver {

        private static ArrayList<File> files = new ArrayList<File>();

        public List<File> getFileList(File file, FileFilter filter) {
            File children[] = null == filter ? file.listFiles() : file.listFiles(filter);

            for (int i = 0; i < children.length; i++) {
                if (children[i].isDirectory()) {
                    new Recursiver().getFileList(children[i], filter);
                } else {
                    files.add(children[i]);
                }
            }

            return files;
        }
    }
    
    /**
	 * 
	 * @Title: getFileContent
	 * @Description: 解析文件类容转为字符串(基于Apatch Tika)
	 * @author: WangShengLi
	 * @param filePath
	 * @return
	 * @return: String
	 */
	public static String getFileContent(String filePath) {
//		try {
//			String content = TikaUtil.parse(filePath);
//			if(content!=null) {
//				content=content.replaceAll("\\s*", "");
//			}
//	    	return content;
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
		return null;
	}
    
	/**
	 *	 读取文件为字符串
	 * @author: WangShengLi
	 *
	 */
	public static String ReadFile(String Path) {
		String laststr = "";
		try (
			FileInputStream fileInputStream = new FileInputStream(Path);
			InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
			BufferedReader reader = new BufferedReader(inputStreamReader);
		) {
			String tempString = null;
			while ((tempString = reader.readLine()) != null) {
				laststr += tempString;
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return laststr;
	}

	/**
	 *	 以行为单位读取文件，读取到最后一行
	 * 
	 * @param filePath
	 * @return
	 */
	public static List<String> readFileContent(String filePath) {
		List<String> listContent = new ArrayList<>();
		try (
			BufferedReader reader = new BufferedReader(new FileReader(filePath));
		){
			String tempString = null;
			int line = 1;
			// 一次读入一行，直到读入null为文件结束
			while ((tempString = reader.readLine()) != null) {
				listContent.add(tempString);
				line++;
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return listContent;
	}

	/**
	 *	 读取指定行数据 ，注意：0为开始行
	 * 
	 * @param filePath
	 * @param lineNumber
	 * @return
	 */
	public static String readLineContent(String filePath, int lineNumber) {
		String lineContent = "";
		try (
			BufferedReader reader = new BufferedReader(new FileReader(filePath));
		){
			int line = 0;
			while (line <= lineNumber) {
				lineContent = reader.readLine();
				line++;
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		} 
		return lineContent;
	}

	/**
	 *	 读取从beginLine到endLine数据（包含beginLine和endLine），注意：0为开始行
	 * 
	 * @param filePath
	 * @param beginLineNumber 开始行
	 * @param endLineNumber   结束行
	 * @return
	 */
	public static List<String> readLinesContent(String filePath, int beginLineNumber, int endLineNumber) {
		List<String> listContent = new ArrayList<>();
		try (
			BufferedReader reader = new BufferedReader(new FileReader(filePath));	
		){
			int count = 0;
			
			String content = reader.readLine();
			while (content != null) {
				if (count >= beginLineNumber && count <= endLineNumber) {
					listContent.add(content);
				}
				content = reader.readLine();
				count++;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return listContent;
	}

	/**
	 *	 读取若干文件中所有数据
	 * 
	 * @param listFilePath
	 * @return
	 */
	public static List<String> readFileContent_list(List<String> listFilePath) {
		List<String> listContent = new ArrayList<>();
		for (String filePath : listFilePath) {
			File file = new File(filePath);
			try(
				BufferedReader reader = new BufferedReader(new FileReader(file));	
			) {
				
				String tempString = null;
				int line = 1;
				// 一次读入一行，直到读入null为文件结束
				while ((tempString = reader.readLine()) != null) {
					listContent.add(tempString);
					line++;
				}
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			} 
		}
		return listContent;
	}
	   
	/**
	 * 	文件数据写入（如果文件夹和文件不存在，则先创建，再写入）
	 * 
	 * @param filePath
	 * @param content
	 * @param flag true:如果文件存在且存在内容，则内容换行追加；false:如果文件存在且存在内容，则内容替换
	 */
	public static void fileLinesWrite(String filePath, String content, boolean flag) {
		FileWriter fw = null;
		try {
			File file = new File(filePath);
			// 如果文件夹不存在，则创建文件夹
			if (!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}
			if (!file.exists()) {// 如果文件不存在，则创建文件,写入第一行内容
				file.createNewFile();
				fw = new FileWriter(file);
			} else {// 如果文件存在,则追加或替换内容
				fw = new FileWriter(file, flag);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		PrintWriter pw = new PrintWriter(fw);
		pw.println(content);
		pw.flush();
		try {
			fw.flush();
			pw.close();
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 *	 写文件
	 * 
	 * @param ins
	 * @param out
	 */
	public static void writeIntoOut(InputStream ins, OutputStream out) {
		byte[] bb = new byte[10 * 1024];
		try {
			int cnt = ins.read(bb);
			while (cnt > 0) {
				out.write(bb, 0, cnt);
				cnt = ins.read(bb);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				out.flush();
				ins.close();
				out.close();
			} catch (IOException e) {
				LoggerUtil.error("流关闭异常",e);
			}
		}
	}

	/**
	 *	 删除文件夹及其下面的子文件夹(只删除文件夹，若文件夹下存在文件IOException)
	 *
	 * @param dir
	 * @throws IOException
	 */
	public static void deleteDir(File dir) throws IOException {
		if (dir.isFile())
			throw new IOException("IOException -> BadInputException: not a directory.");
		File[] files = dir.listFiles();
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				File file = files[i];
				if (file.isFile()) {
					file.delete();
				} else {
					deleteDir(file);
				}
			}
		}
		dir.delete();
	}

	/**
	 * 	复制文件
	 *
	 * @param src
	 * @param dst
	 * @throws Exception
	 */
	public static void copy(File src, File dst) throws IOException {
		try (
			InputStream	in = new BufferedInputStream(new FileInputStream(src), FILE_BUFFER_SIZE);
			OutputStream out = new BufferedOutputStream(new FileOutputStream(dst), FILE_BUFFER_SIZE);
		) {
			byte[] buffer = new byte[FILE_BUFFER_SIZE];
			int len = 0;
			while ((len = in.read(buffer)) > 0) {
				out.write(buffer, 0, len);
			}
		} catch (IOException e) {
			LoggerUtil.debug("文件复制异常", e);
			throw e;
		}
	}

	/**
	 * 	文件或者目录重命名
	 * 
	 * @param oldFilePath 旧文件路径
	 * @param newName     新的文件名,可以是单个文件名和绝对路径
	 * @return
	 */
	public static boolean renameTo(String oldFilePath, String newName) {
		try {
			File oldFile = new File(oldFilePath);
			// 若文件存在
			if (oldFile.exists()) {
				// 判断是全路径还是文件名
				if (newName.indexOf("/") < 0 && newName.indexOf("\\") < 0) {
					// 单文件名，判断是windows还是Linux系统
					String absolutePath = oldFile.getAbsolutePath();
					if (newName.indexOf("/") > 0) {
						// Linux系统
						newName = absolutePath.substring(0, absolutePath.lastIndexOf("/") + 1) + newName;
					} else {
						newName = absolutePath.substring(0, absolutePath.lastIndexOf("\\") + 1) + newName;
					}
				}
				File file = new File(newName);
				// 判断重命名后的文件是否存在
				if (file.exists()) {
					LoggerUtil.warn("该文件已存在,不能重命名");
				} else {
					// 不存在，重命名
					return oldFile.renameTo(file);
				}
			} else {
				LoggerUtil.warn("原该文件不存在,不能重命名");
			}
		} catch (Exception e) {
			LoggerUtil.error(e);
		}
		return false;
	}

	/**
	 * 	如果目录不存在，就创建文件
	 * @param dirPath
	 * @return
	 */
	public static String mkdirs(String dirPath) {
		try {
			File file = new File(dirPath);
			if (!file.exists()) {
				file.mkdirs();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return dirPath;
	}

}
